package com.wjk.kylin.mall.common.redis.component;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 订单号等生成器
 */
@Component
public class BusinessNoGenerator {
    public static final String DAY_PATTERN = "yyyyMMddHHmmssSSS";
    public static final Integer[] MAX_NUM = {9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999};

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 默认 3位递增
     *
     * @param businessType
     * @return
     */
    public String generate(BusinessTypeEnum businessType) {
        return generate(businessType, 3);
    }

    /**
     * @param businessType 业务类型枚举
     * @param digit        业务序号位数
     * @return
     */
    public String generate(BusinessTypeEnum businessType, Integer digit) {
        if (digit < 1 || digit > MAX_NUM.length) {
            throw new UnsupportedOperationException();
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DAY_PATTERN);
        LocalDateTime now = LocalDateTime.now(ZoneOffset.of("+8"));
        String date = now.format(formatter);

        long number = getNumber(businessType, date);

        int maxNum = MAX_NUM[digit - 1];
        if (number > maxNum) {
            return generate(businessType, digit, maxNum, formatter, now);
        }

        return date + businessType.getValue() + String.format("%0" + digit + "d", number);
    }


    /**
     * @param businessType 业务类型枚举
     * @param digit        业务序号位数
     * @param maxNum       位数的最大值
     * @param formatter    时间格式
     * @param now          当前时间
     * @return
     */
    private String generate(BusinessTypeEnum businessType,
                            Integer digit,
                            int maxNum,
                            DateTimeFormatter formatter,
                            LocalDateTime now) {
        now = now.plusNanos(1000000);//当前时间增加1毫秒
        String date = now.format(formatter);

        long number = getNumber(businessType, date);

        if (number > maxNum) {
            return generate(businessType, digit, maxNum, formatter, now);
        }

        return date + businessType.getValue() + String.format("%0" + digit + "d", number);
    }


    /**
     * @param businessType
     * @param date
     * @return
     */
    private long getNumber(BusinessTypeEnum businessType, String date) {
        String key = businessType.getPrefix() + ":" + businessType.getCode() + ":" + date;
        RedisAtomicLong atomicLong = new RedisAtomicLong(key,
                Objects.requireNonNull(redisTemplate.getConnectionFactory()));
        long number = atomicLong.incrementAndGet();

        if (atomicLong.longValue() <= 1) {
            atomicLong.expire(5, TimeUnit.MINUTES);
        }
        return number;
    }

}
